package com.tech.pattern.singleton;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
/**
 * 
 * <p>Title: SingletonIdler </p>
 * <p>Description: 
 * 懒汉式
 * (1)验证懒汉式，存在线程安全问题。
 * (2)验证时采用了闭锁的方式，为了让主线程等待其他线程结束后在统计结果。
 * (3)通过加锁的方式解决这种线程安全问题
 * (4)通过双从加锁进一步优化。
 * </p>
 * Date: 2017年8月4日下午4:13:49
 * @author zl
 * @version 1.0 
 * Significant Modify：
 * Date               Author           Content
 * ==========================================================
 * 2017年8月4日           zl        创建文件,实现基本功能
 * 
 * ==========================================================
 */
public class SingletonIdler {
	// 1 私有化构造函数
	private SingletonIdler() {
	}

	// 2 私有化实例对象
	private static SingletonIdler instance = null;

	// 3 对外提供公共的方法
	public static SingletonIdler getInstance() {
		synchronized (SingletonIdler.class) {
			if (instance == null) {
				instance = new SingletonIdler();
				return instance;
			}
		}
		return instance;
	}

	public static void main(String[] args) throws InterruptedException {
		// 验证：单线程环境下懒汉式不存在线程安全问题
		/*
		 * SingletonIdler single1 = SingletonIdler.getInstance(); 
		 * SingletonIdler single2 = SingletonIdler.getInstance();
		 * System.out.println(single1==single2);
		 */
		CountDownLatch latch = new CountDownLatch(10);// 计算线程当前线程在通过等待之前需要被调用的次数。
		ThreadSingleIdler t1 = new ThreadSingleIdler(latch);
		for (int i = 0; i < 10; i++) {
			new Thread(t1).start();
		}
		latch.await();
		System.out.println("set:" + t1.set);
	}

}

class ThreadSingleIdler implements Runnable {
	private CountDownLatch latch;

	public ThreadSingleIdler(CountDownLatch latch) {
		this.latch = latch;
	}

	// 采用Set集合辅助验证，因为set集合不允许重复。多线程环境下set结合如果存入多个。证明返回的不是同一个实例存在线程安全问题
	Set<SingletonIdler> set = new HashSet<SingletonIdler>();

	@Override
	public void run() {
		try {
			Thread.sleep(1000);
			SingletonIdler single1 = SingletonIdler.getInstance();
			set.add(single1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			latch.countDown(); // 线程每执行一次数量减少一次，但数量达到0时释放所有等待的线程。
		}
	}
}
